{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 元素级运算\n",
    "- Python 中的方式\n",
    "假设你有一个数字列表，你想向列表中的每一项加上 5 。如果没有 NumPy，你可以像下面这样做"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "values = [1,2,3,4,5]\n",
    "for i in range(len(values)):\n",
    "    values[i] += 5\n",
    "\n",
    "# 现在的值为 [6,7,8,9,10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6, 7, 8, 9, 10]\n"
     ]
    }
   ],
   "source": [
    "print(values)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这是讲得通的，但是你要编写很多代码，而且因为它是纯 Python，所以运行的很慢。\n",
    "\n",
    "**Note: **以防你不习惯使用像 += 这样的运算符，它的意思是\"添加这两项，然后将结果保存在左边的项中\"。  \n",
    "这是 values[i] = values[i] + 5 的一种更简洁的写法。你在这些示例中看到的代码尽可能地使用这样的运算符。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NumPy 中的方式\n",
    "\n",
    "在 NumPy 中，我们可以这么做："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "values = [1,2,3,4,5]\n",
    "values = np.array(values) + 5\n",
    "\n",
    "# 现在值是包含 [6,7,8,9,10] 的一个 ndarray"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 6  7  8  9 10]\n"
     ]
    }
   ],
   "source": [
    "print values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建该数组可能看起来很奇怪，但通常你总是要将数据存储在 ndarray 中的。所以如果你已经有一个名为 values 的 ndarray，你可以这么做："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "values += 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[11 12 13 14 15]\n"
     ]
    }
   ],
   "source": [
    "print values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们应该指出，NumPy 实际上有用于添加、乘法等的函数。但它也支持使用标准的数学运算符。 所以以下两行是等价的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'some_array' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-9-8a04e47feb67>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmultiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msome_array\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msome_array\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'some_array' is not defined"
     ]
    }
   ],
   "source": [
    "x = np.multiply(some_array, 5)\n",
    "x = some_array * 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们通常会使用运算符而不是函数，因为它们更方便键入，也更容易阅读，不过这只是个人偏好。再看一个使用标量和 ndarrays 进行运算的例子。假设你有一个矩阵 m 并且你想重用它，但首先你需要将其所有值设为零。这很简单，只需给它乘以零，并将结果分配回矩阵就行了，如下所示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'm' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-10-4e392172238b>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mm\u001b[0m \u001b[0;34m*=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;31m# 现在 m 中的每个元素都是 0，无论它有多少维度\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'm' is not defined"
     ]
    }
   ],
   "source": [
    "m *= 0\n",
    "\n",
    "# 现在 m 中的每个元素都是 0，无论它有多少维度"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 元素级矩阵运算\n",
    "与标量和矩阵一起使用的相同函数和运算符也适用于其他维度。你只需要确保执行运算的项目具有兼容的形状。\n",
    "\n",
    "假设你想得到矩阵的平方值。方法是 x = m * m（或者如果你要将值分配回 m，则是 m *= m）\n",
    "\n",
    "这是可以运作的，因为它是两个形状相同的矩阵之间的元素乘法。（在这个例子中，它们的形状相同，是因为它们实际上是相同的对象。）\n",
    "\n",
    "\n",
    "\n",
    "看看视频中的一个示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 3,  7],\n",
       "       [11, 15]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([[1,3],[5,7]])\n",
    "a\n",
    "# 显示以下结果：\n",
    "# array([[1, 3],\n",
    "#        [5, 7]])\n",
    "\n",
    "b = np.array([[2,4],[6,8]])\n",
    "b\n",
    "# 显示以下结果：\n",
    "# array([[2, 4],\n",
    "#        [6, 8]])\n",
    "\n",
    "a + b\n",
    "# 显示以下结果：\n",
    "#      array([[ 3,  7],\n",
    "#             [11, 15]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果您尝试使用不兼容的形状，就像视频中的另一个示例一样，你会收到一个错误："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "operands could not be broadcast together with shapes (2,2) (3,3) ",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-afe11d705bd6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     19\u001b[0m \u001b[0;31m#  (3, 3)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     20\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 21\u001b[0;31m \u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     22\u001b[0m \u001b[0;31m# 显示以下结果：\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     23\u001b[0m \u001b[0;31m# ValueError: operands could not be broadcast together with shapes (2,2) (3,3)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (2,2) (3,3) "
     ]
    }
   ],
   "source": [
    "a = np.array([[1,3],[5,7]])\n",
    "a\n",
    "# 显示以下结果：\n",
    "# array([[1, 3],\n",
    "#        [5, 7]])\n",
    "c = np.array([[2,3,6],[4,5,9],[1,8,7]])\n",
    "c\n",
    "# 显示以下结果：\n",
    "# array([[2, 3, 6],\n",
    "#        [4, 5, 9],\n",
    "#        [1, 8, 7]])\n",
    "\n",
    "a.shape\n",
    "# 显示以下结果：\n",
    "#  (2, 2)\n",
    "\n",
    "c.shape\n",
    "# 显示以下结果：\n",
    "#  (3, 3)\n",
    "\n",
    "a + c\n",
    "# 显示以下结果：\n",
    "# ValueError: operands could not be broadcast together with shapes (2,2) (3,3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你会在后面的课程中详细了解“不能一起广播”的意义，现在只需注意这两种形状是不同的，因此我们无法执行元素级运算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
